; *******************************************************************
; * exp3_3.asm
; * LLP STUDIO Chen Zhepeng
; * V2.1
; * 2023-10-12 (Updated)
; * 共阳数码管右对齐显示0 ~ F，每隔0.5 s输出一个数据，当显示
; * 8 9 A B C D E F后全部熄灭，而后从头开始继续显示
; *******************************************************************
; * V2.1, 2023-10-12: 解决显示8 9 A B C D E F后能够出现0.5 s的全灭
; * V2.0, 2023-10-09: 解决只显示1位的问题
; * V1.0, 2023-09-29: Initial version.
; *******************************************************************

P4         DATA 0C0H
P6         DATA 0E8H
P4M1       DATA 0B3H
P4M0       DATA 0B4H
P6M1       DATA 0CBH
P6M0       DATA 0CCH
HC595_SI   BIT  P4.4  ; 74HC595串行输入端
HC595_SCK  BIT  P4.2  ; 74HC595移位时钟输入
HC595_RCK  BIT  P4.3  ; 74HC595锁存时钟输入
DISP_BLACK EQU  10H   ; 对应段码表0FFH（全黑）
NIXIE8     DATA 30H   ; 显示缓冲30H ~ 37H
disp_index DATA 38H   ; 显示位索引
delay_cnt  EQU  74H   ; 延时计数单元，每2 ms加1，== 250即延时0.5 s

ORG 0000H
LJMP Main
ORG 0100H
Main:
; P4口推挽
MOV P4M1, #00H
MOV P4M0, #0FFH
; 设置P6口为推挽输出
MOV P6M1, #00H
MOV P6M0, #0FFH
;MOV R0, #8  ; 位码计数器
;MOV R1, #1  ; 段码计数器

Main1:
MOV disp_index, #0  ; 消隐
MOV R0, #NIXIE8  ; 灭灯
MOV R2, #8  ; 8个数码管，执行8次
ClearLoop:
MOV @R0, #DISP_BLACK
INC R0
DJNZ R2, ClearLoop
LCALL ScanDisp
LCALL DELAY500MS
MOV delay_cnt, #0  ; 延时计数器初值为0
MOV NIXIE8 + 7, #1  ; 最右端数码管从1开始显示
SETB P4.0  ; 关闭8个LED

MainLoop:
;MOV R2, #1  ; 目前显示的位数
;CJNE R2, #8, Disp
;Disp:
LCALL ScanDisp  ; 2 ms扫描显示一位
; 延时2 ms * 250
LCALL DELAY2MS
;INC R2
;LCALL DELAY500MS
;LJMP MainLoop
INC delay_cnt  ; 延时计数
MOV A, delay_cnt
CJNE A, #250, MainLoop
MOV delay_cnt, #0

; 移位显示
MOV NIXIE8, NIXIE8 + 1
MOV NIXIE8 + 1, NIXIE8 + 2
MOV NIXIE8 + 2, NIXIE8 + 3
MOV NIXIE8 + 3, NIXIE8 + 4
MOV NIXIE8 + 4, NIXIE8 + 5
MOV NIXIE8 + 5, NIXIE8 + 6
MOV NIXIE8 + 6, NIXIE8 + 7
INC NIXIE8 + 7
MOV A, NIXIE8 + 7
CJNE A, #DISP_BLACK, MainLoop  ; 显示到F，从头开始
;LCALL DELAY500MS
LJMP Main1

PosTable:
DB 80H, 40H, 20H, 10H, 08H, 04H, 02H, 01H
;PosTable2:
;DB 00H, 0FFH, 7FH, 3FH, 1FH, 0FH, 07H, 03H, 01H
SegTable:
DB 0XC0, 0XF9, 0XA4, 0XB0, 0X99, 0X92, 0X82, 0XF8
DB 0X80, 0X90, 0X88, 0X83, 0XC6, 0XA1, 0X86, 0X8E
DB 0FFH  ; 全黑

; * @brief       向74HC595D发送一个字节
; * @param       ACC: 要发送的字节数据（存放在累加器中）
; * @retval      无
Hc595SendByte:
PUSH 02H
MOV R2, #8
Hc595SendLoop:
RLC A
MOV HC595_SI, C
SETB HC595_SCK
CLR HC595_SCK
DJNZ R2, Hc595SendLoop
POP 02H
RET

; * @brief       数码管动态显示
; * @param       无
; * @retval      无
ScanDisp:
PUSH DPH
PUSH DPL
PUSH 00H  ;R0入栈
MOV A, #00H
LCALL Hc595SendByte  ; 输出点阵位码，关闭点阵
MOV DPTR, #PosTable
;MOV A, R0
MOV A, disp_index
MOVC A, @A + DPTR
LCALL Hc595SendByte  ; 输出位码
CLR HC595_RCK
NOP
SETB HC595_RCK  ; 上升沿并行锁存到输出端
NOP
CLR HC595_RCK  ; 锁存输出数据
MOV DPTR, #SegTable
;MOV A, R1
MOV A, disp_index
ADD A, #NIXIE8  ; 根据disp_index指示的第几个数码管，
MOV R0, A  ; 定位要显示的数码管
MOV A, @R0
MOVC A, @A + DPTR
MOV P6, A  ; 输出段码
INC disp_index
MOV A, disp_index
ANL A, #0F8H
JZ QuitScanDisp  ; disp_index == 0 ~ 7跳转
; if (disp_index >= 8)
; {
MOV disp_index, #0  ; 8位结束回0
; }
; else
; {
QuitScanDisp:
POP 00H  ; R0出栈
POP DPL
POP DPH
RET
; }

;DEC R0
;INC R1
;CJNE R0, R2, NotResetR0
;MOV R0, #8
;NotResetR0:
;CJNE R1, #16, NotResetR1
;MOV R1, #1
;NotResetR1:
;RET

; * @brief       2 ms延时（由STC-ISP生成）
; * @param       无
; * @retval      无
DELAY2MS:			;@24.000MHz
	NOP
	PUSH	30H
	PUSH	31H
	MOV		30H,#63
	MOV		31H,#82
NEXT:
	DJNZ	31H,NEXT
	DJNZ	30H,NEXT
	POP		31H
	POP		30H
	RET

; * @brief       0.5 s延时（由STC-ISP生成）
; * @param       无
; * @retval      无
DELAY500MS:			;@24.000MHz
	NOP
	NOP
	PUSH	30H
	PUSH	31H
	PUSH	32H
	MOV		30H,#61
	MOV		31H,#225
	MOV		32H,#60
NEXT2:
	DJNZ	32H,NEXT2
	DJNZ	31H,NEXT2
	DJNZ	30H,NEXT2
	POP		32H
	POP		31H
	POP		30H
	RET


END
